﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Validation;
using System.Linq;
using KPIS.GERP.Models;
using KPIS.GERP.Models.HRM;
using System.Threading;

namespace KPIS.GERP.TaskScheduler
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            Console.Title = "GERP Task Scheduler";
            Console.BackgroundColor = ConsoleColor.DarkBlue;
            Console.WriteLine("GERP Task Sceduler");
            string connectionString = null;
            string dbName = null;
            string serverName = null;
            int cmdId = 0;
            int intEmpStatusSeq = -1;
            string errorStr = "";

            try
            {
                // 2 param = db config
                if (args != null && args.Length >= 2)
                {
                    dbName = args[0];
                    serverName = args[1];
                }

                // 1 param or 3 param
                if (args != null && (args.Length == 1 || args.Length == 3))
                {
                    var argCmdId = args.Length == 1 ? args[0] : args[2];
                    Int32.TryParse(argCmdId, out cmdId);
                }
            }
            catch (Exception ex)
            {
                errorStr += ex.Message;
                Console.WriteLine("Error#1:" + ex.Message);
                Console.ReadLine();
                return;
            }

            if (!string.IsNullOrWhiteSpace(dbName) && !string.IsNullOrWhiteSpace(serverName)) connectionString = string.Format("Database={0};Server={1};User Id=sa;Password=root123456789;Timeout=120;", dbName, serverName);

            Console.WriteLine("Start Task Scheduler on {0}{1}.", DateTime.Now, cmdId != 0 ? " for " + cmdId : "");
            Console.ResetColor();
            if (string.IsNullOrWhiteSpace(dbName) || string.IsNullOrWhiteSpace(serverName))
            {
                Console.WriteLine("Please pass dbName, serverName as parameter");
            }

            Console.WriteLine("Db:{0}, Server:{1}", dbName, serverName);

            using (GERPContext db = new GERPContext(true, connectionString))
            {
                IQueryable<PsCommand> query;
                List<PsCommand> cmdList = new List<PsCommand>();
                int commandSequence = 1;

                try
                {
                    Console.WriteLine("Open connection, this may take a minute...");

                    db.ScUsers.FirstOrDefault();

                    Console.WriteLine("Success.");

                }
                catch (Exception ex)
                {
                    errorStr += ex.Message;
                    Console.WriteLine("Error#2:" + ex.Message);
                    Console.ReadLine();
                    return;
                }

                try
                {
                    query = cmdId != 0 ? db.PsCommands.Where(o => o.CmdId == cmdId) : db.PsCommands;

                    // get only approved
                    cmdList = query.Where(o => o.RecordStatus == "A").ToList();

                    // W = not approve, A = approved, R = Effected/Executed
                    cmdList = cmdList.Where(o => o.CmdStatus == "A").ToList();

                    Console.WriteLine("Found {0} commands new approved to execute.", cmdList.Count);

                }
                catch (Exception ex)
                {
                    errorStr += ex.Message;
                    Console.WriteLine("Error#3:" + ex.Message);
                    Console.ReadLine();
                    return;
                }

                foreach (PsCommand cmd in cmdList)
                {
                    List<PsCommandDtls> cmddList = new List<PsCommandDtls>();
                    try
                    {
                        // get only approved
                        cmddList = cmd.col_hrm_ps_command_dtls.Where(m => m.RecordStatus == "W").ToList();

                        Console.WriteLine("#{0}: Command to {1} employees.", commandSequence++, cmddList.Count);

                        // get is in time
                        cmddList = cmddList.Where(m => m.StartDate <= DateTime.Now).ToList();
                    }
                    catch (Exception ex)
                    {
                        errorStr += ex.Message;
                        Console.WriteLine("Error#4:" + ex.Message);
                        Console.ReadLine();
                        return;
                    }

                    foreach (PsCommandDtls cmdd in cmddList)
                    {
                        Employee emp;
                        try
                        {
                            emp = db.Employees.Find(cmdd.EmpId);
                            // Interlim resolve
                            //[TaxPayer,จำนวนเลขประจำตัวผู้เสียภาษีอากรน้อยกว่าที่กำหนด]
                            //[Social,จำนวนเลขประกันสังคมน้อยกว่าที่กำหนด]
                            //[Official,จำนวนเลขประจำตัวพนักงานน้อยกว่าที่กำหนด]
                            if (string.IsNullOrWhiteSpace(emp.TaxPayer)) emp.TaxPayer = "0000000000000";
                            if (string.IsNullOrWhiteSpace(emp.Social)) emp.Social = "0000000000000";
                            if (string.IsNullOrWhiteSpace(emp.Official)) emp.Official = "0000000000000";
                            else if (emp.Official.Length < 13) emp.Official = emp.Official.PadRight(13, '0');
                            if (emp.GenderId == null) emp.GenderId = 1;

                            Console.WriteLine("Emp '{0}', grpid {1}, typeid {2}", emp.Citizen, cmd.HrmPsCommandTypes.CmdGroupId, cmd.CmdTypeId);

                        }
                        catch (Exception ex)
                        {
                            errorStr += ex.Message;
                            Console.WriteLine("Error#5:" + ex.Message);
                            Console.ReadLine();
                            return;
                        }
                        switch (cmd.HrmPsCommandTypes.CmdGroupId)
                        {
                            case 1: //บรรจุ
                            case 2: //โยกย้าย
                                try
                                {
                                    intEmpStatusSeq = 101;

                                    emp.PosId = cmdd.NewPosId;
                                    emp.ClassId = cmdd.NewClassId;
                                    emp.ExecPosId = db.ExecutivePositions.FirstOrDefault(m => m.Name == cmdd.NewExecPosName).ExecPosId;
                                    emp.WorkingJobSiteId = cmdd.NewWorkingJobSiteId;
                                    emp.Salary = Convert.ToDecimal(cmdd.NewSalary);
                                    emp.EmpStatusId = intEmpStatusSeq;

                                    EmpPositionHistory his = new EmpPositionHistory();
                                    his.EmpId = cmdd.EmpId;
                                    his.StartDate = cmdd.StartDate;
                                    his.EndDate = cmdd.EndDate;
                                    his.CmdDtlsId = cmdd.CmdDtlsId;
                                    his.CmdRefNo = cmd.CmdRefNo;
                                    his.CmdDate = cmd.ApprovedDate;
                                    his.CmdName = cmd.CmdName;
                                    his.CmdPosRef = cmdd.NewPosRef;
                                    his.CmdPosName = cmdd.NewPosName;
                                    his.CmdClassId = cmdd.NewClassId;
                                    his.CmdClassName = cmdd.NewClass.ClassName;
                                    his.CmdJobSiteId = cmdd.NewJobSiteId;
                                    his.CmdJobSiteName = cmdd.NewJobSiteName;
                                    his.CmdWorkingJobSiteName = cmdd.NewWorkingJobSiteName;
                                    his.CmdDepName = cmdd.NewDepName;
                                    his.CmdMisName = null; // ไม่มี Newmis_name
                                    his.CmdFieldId = null; // ไม่มี Newfield_seq
                                    his.CmdFieldName = null; // ไม่มี Newfield_name
                                    his.CmdExecId = cmd.CmdId;
                                    his.CmdExecName = cmdd.NewExecPosName;
                                    his.CmdSalary = cmdd.NewSalary;
                                    his.CmdSalaryPosition = cmdd.NewExecSalary;
                                    his.RecordStatus = "U";
                                    his.CreatedBy = -1;
                                    his.CreatedWhen = DateTime.Now;

                                    db.PsEmpPositionHistories.Add(his);

                                    cmdd.RecordStatus = "A";
                                }
                                catch (Exception ex)
                                {
                                    errorStr += ex.Message;
                                    Console.WriteLine("Error#6:" + ex.Message);
                                    Console.ReadLine();
                                    return;
                                }
                                break;
                            case 5: //เงินเดือน
                                try
                                {
                                    emp.Salary = (Decimal?) cmdd.NewSalary;

                                    PsEmpSalaryHistory salaryHis = new PsEmpSalaryHistory();

                                    salaryHis.EmpId = cmdd.EmpId;
                                    salaryHis.StartDate = cmdd.StartDate;
                                    salaryHis.EndDate = cmdd.EndDate;
                                    salaryHis.CmdRefNo = cmd.CmdRefNo;
                                    salaryHis.CmdName = cmd.CmdName;
                                    salaryHis.CmdDate = cmd.ApprovedDate;
                                    salaryHis.PosRef = cmdd.NewPosRef;
                                    salaryHis.PosName = cmdd.NewPosName;
                                    salaryHis.ClassId = cmdd.NewClassId;
                                    salaryHis.ClassName = cmdd.NewClass.ClassName;
                                    salaryHis.JobSiteId = cmdd.NewJobSiteId;
                                    salaryHis.JobSiteName = cmdd.NewJobSiteName;
                                    salaryHis.SalaryNew = cmdd.NewSalary;
                                    salaryHis.SalaryOld = cmdd.OldSalary;
                                    salaryHis.SalaryPercentUp = null;
                                    salaryHis.SalaryUp = cmdd.NewSalary - cmdd.OldSalary;
                                    salaryHis.SalaryMidpoint = null;
                                    salaryHis.SalaryExtra = null;
                                    //salaryHis.SalaryExtraId = null;
                                    salaryHis.TotalScore = null;
                                    salaryHis.RecordStatus = "U";
                                    salaryHis.CreatedBy = -1;
                                    salaryHis.CreatedWhen = DateTime.Now;

                                    db.PsEmpSalaryHistories.Add(salaryHis);

                                    cmdd.RecordStatus = "A";
                                }
                                catch (Exception ex)
                                {
                                    errorStr += ex.Message;
                                    Console.WriteLine("Error#7:" + ex.Message);
                                    Console.ReadLine();
                                    return;
                                }
                                break;
                            case 6: //ออกจากราชการ
                                try
                                {
                                    switch (cmd.CmdTypeId)
                                    {
                                        case 1700: //เกษียณ
                                            emp.QuitDate = cmdd.StartDate;
                                            intEmpStatusSeq = 901;
                                            break;
                                        case 305: //ให้โอน
                                            intEmpStatusSeq = 907;
                                            break;
                                        case 1701: //ให้ลาออกได้
                                        case 1702: //ให้ออกเพราะไม่ผ่านโปร
                                        case 1703: //ให้ออกเพราะคุณสมบัติไม่เหมาะสม
                                        case 1705: //ไปเป็นทหาร
                                            emp.QuitDate = cmdd.StartDate;
                                            intEmpStatusSeq = 903;
                                            break;
                                        case 1704: //เกษียณก่อนกำหนด
                                            emp.QuitDate = cmdd.StartDate;
                                            intEmpStatusSeq = 909;
                                            break;
                                        default:
                                            intEmpStatusSeq = 101;
                                            break;
                                    }

                                    decimal result;
                                    Decimal.TryParse((cmdd.NewSalary ?? 0).ToString(), out result);
                                    emp.Salary = result;
                                    cmdd.RecordStatus = "A";

                                }
                                catch (Exception ex)
                                {
                                    errorStr += ex.Message;
                                    Console.WriteLine("Error#8:" + ex.Message);
                                    Console.ReadLine();
                                    return;
                                }
                                break;
                            case 7: //โทษวินัย
                                try
                                {
                                    switch (cmd.PenaltyId)
                                    {
                                        case 1: // penseq = 1 พักราชการ
                                            intEmpStatusSeq = 302;
                                            break;
                                        case 3: // penseq = 1 ไล่ออก
                                            intEmpStatusSeq = 905;
                                            break;
                                        case 5: // penseq = 3 ให้ออก
                                            intEmpStatusSeq = 903;
                                            break;
                                        default:
                                            intEmpStatusSeq = 101;
                                            break;
                                    }

                                    cmdd.RecordStatus = "A";
                                }
                                catch (Exception ex)
                                {
                                    errorStr += ex.Message;
                                    Console.WriteLine("Error#9:" + ex.Message);
                                    Console.ReadLine();
                                    return;
                                }
                                break;
                        }
                        try
                        {
                            if (intEmpStatusSeq != -1) emp.EmpStatusId = intEmpStatusSeq;

                            cmdd.Remarks = "ระบบนำคำสั่งไปใช้เมื่อ " + DateTime.Now.ToString("dd/MMM/yyyy HH:mm") + ", " + cmdd.Remarks;

                        }
                        catch (Exception ex)
                        {
                            errorStr += ex.Message;
                            Console.WriteLine("Error#9:" + ex.Message);
                            Console.ReadLine();
                            return;
                        }
                    }
                    cmd.CmdStatus = "R";
                }

                try
                {
                    // check EndDate to normal status
                    var cmdList2 = (from c in db.PsCommands
                                    join cd in db.PsCommandDtls on c.CmdId equals cd.CmdId
                                    where c.RecordStatus == "A"
                                          && (c.CmdStatus == "A" || c.CmdStatus == "R")
                                          && (cd.EndDate != null
                                                  ? cd.EndDate.Value
                                                  : new DateTime(3000, 1, 1)) <= DateTime.Today
                                    select c).ToList();

                    Console.WriteLine("Found {0} commands that reached end date.", cmdList2.Count);

                    commandSequence = 1;
                    foreach (PsCommand cmd in cmdList2)
                    {
                        foreach (PsCommandDtls cmdd in cmd.col_hrm_ps_command_dtls)
                        {
                            Employee emp = db.Employees.Find(cmdd.EmpId);
                            Console.WriteLine("#{1}: Set employee {0} back to normal.", emp.Citizen, commandSequence++);

                            emp.EmpStatusId = 101; // ปฎิบัติงาน
                        }
                    }

                }
                catch (Exception ex)
                {
                    errorStr += ex.Message;
                    Console.WriteLine("Error#10:" + ex.Message);
                    Console.ReadLine();
                    return;
                }
                try
                {
                    db.SaveChanges();
                }
                catch (DbEntityValidationException ex)
                {
                    foreach (var v in ex.EntityValidationErrors)
                    {
                        foreach (var v2 in v.ValidationErrors)
                        {
                            errorStr += "[" + v2.PropertyName + "," + v2.ErrorMessage + "]\r\n";
                        }
                    }
                }
                catch (Exception ex)
                {
                    errorStr += "Error[" + ex.Message + "]";
                    if (ex.InnerException != null) errorStr += "\r\nError[" + ex.InnerException.Message + "]";
                    if (ex.InnerException != null && ex.InnerException.InnerException != null) errorStr += "\r\nError[" + ex.InnerException.InnerException.Message + "]";
                }

                Console.WriteLine("Error:{0}", string.IsNullOrWhiteSpace(errorStr) ? "Not found" : errorStr);
                Console.WriteLine("Completed on {0}.", DateTime.Now);
                Console.WriteLine("This is daily task and done work completed.");
                Console.WriteLine("Press any key to close...");
                Console.Read();
            } 
        }
    }
}